package com.bobo.controller.base;

import com.bobo.annotations.*;
import com.bobo.util.UploadFiles;
import com.bobo.util.Utils;
import org.apache.log4j.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by anting on 16/10/24.
 */


public class BaseServlet extends HttpServlet {

    static Logger log = Logger.getLogger(BaseServlet.class);

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        mapping(request, response, "POST");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        mapping(request, response, "GET");
    }


    private void mapping(HttpServletRequest request, HttpServletResponse response, String type) throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        try {
            String[] path = request.getRequestURI().split("/");
            String pathMethod = "";

            String[] end = {".css", ".js", ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".jsp"};

            pathMethod = path[path.length - 1];

            boolean isPublic = false;

            for (String s : end) {
                if (pathMethod.endsWith(s)) {
                    isPublic = true;
                    break;
                }
            }

            if (!isPublic) {

                boolean isOver = false;
                Object result = "";

                for (Method m : this.getClass().getDeclaredMethods()) {
                    if (m.isAnnotationPresent(RequestMapping.class)) {
                        RequestMapping requestMapping = m.getAnnotation(RequestMapping.class);
                        // 获取定义的 方法类型 get / post
                        RequestMethod[] requestMethod = requestMapping.method();
                        for (RequestMethod r : requestMethod) {
                            //  方法类型是否匹配                         判断 注解中value 是否存在 对应的链接地址
                            if (r.toString().equals(type) && Arrays.asList(requestMapping.value()).contains("/" + pathMethod)) {
                                isOver = true;
                                //获取这个方法的参数列表  ru:   public String del(HttpServletRequest request, HttpServletResponse response){  中的request和 response
                                Class<?>[] parameterTypes = m.getParameterTypes();
                                Annotation[][] an = m.getParameterAnnotations();
                                //invoke 时用到的参数
                                Object[] obj = new Object[parameterTypes.length];
                                comparison(request, response, parameterTypes, an, obj);
                                result = m.invoke(this, obj);
                                asynchronous(m, request, response, result);
                            }
                        }
                    }
                    //跳出循环
                    if (isOver) {
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //获取参数
    private void comparison(HttpServletRequest request, HttpServletResponse response, Class<?>[] parameterTypes, Annotation[][] an, Object[] obj) throws IOException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //invoke 时用到的参数
        for (int i = 0; i < parameterTypes.length; i++) {
            Class clz = parameterTypes[i];
            Annotation[] ann = an[i];
            if ("javax.servlet.http.HttpServletRequest".equals(clz.getName())) {
                obj[i] = request;
            }
            if ("javax.servlet.http.HttpServletResponse".equals(clz.getName())) {
                obj[i] = response;
            } else if (ann.length > 0) {
                BackParameter(request,ann,clz,obj,i);
            } else {
                Utils.toLower(clz.getSimpleName());
            }
        }

    }

    /**
     * 返回的参数
     * @param request request
     * @param ann 参数注解
     * @param clz 类类型
     * @param obj 返回的参数数组
     * @param i 循环次数
     * @throws IOException 异常
     */
    private void BackParameter(HttpServletRequest request, Annotation[] ann,Class clz,Object[] obj,int i) throws IOException {
        Map<String, String[]> forms = UploadFiles.UploadForms(request);
        if(forms.size()<=0) return;
        Annotation ans = ann[0];
        if (ans instanceof Prm) {
            Prm prm = (Prm) ans;
            String prt = prm.value();
            if (Utils.isModelC(clz)) {
                obj[i] = model(forms, clz, prt);
            } else {
                if (forms.containsKey(prt)) {
                    String[] fv = forms.get(prt);
                    Object changeType = changeType(clz, fv[0]);
                    obj[i] = changeType;
                }
            }
        }
    }

    //判断是否为异步 然后执行异步操作
    private void asynchronous(Method m,HttpServletRequest request, HttpServletResponse response,Object result) throws IOException, ServletException {
        // 判断是否为异步请求 需要返回字符串
        if (m.isAnnotationPresent(RequestBody.class)) {
            PrintWriter out = response.getWriter();
            out.write(result.toString());
        } else if (result.toString().startsWith("redirect:")) {
            response.sendRedirect(result.toString().replace("redirect:", ""));
        } else {
            request.getRequestDispatcher("/" + result.toString() + ".jsp").forward(request, response);
        }
    }

    private Object model(Map<String, String[]> forms,Class clz,String nm) {
        Object o = null;
        try {
            o = clz.newInstance();
            //获取类的成员变量
            Field[] fields = clz.getDeclaredFields();
            for (Field f : fields) {
                String fieldName = f.getName();
                String name = nm + "." + fieldName;
                Class fieldType = f.getType();
                Method method = clz.getDeclaredMethod("set" + Utils.captureName(fieldName), fieldType);
                //成员变量为模型类
                if (Utils.isModel(f)) {
                    Object oo = model(forms, f.getType(), name);
                    method.invoke(o,oo);
                }
                if (Utils.isCollection(f.getType())) {
                    setList(f,forms,name,method,o);
                } else if(forms.containsKey(name)){
                        String[] fv = forms.get(name);
                        Object changeType = changeType(fieldType, fv[0]);
                        method.invoke(o,changeType);
                    }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return o;
    }

    private void setList(Field f,Map<String, String[]> forms,String name,Method method,Object o) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        if(f.isAnnotationPresent(Lst.class)){
            Lst annotation = f.getAnnotation(Lst.class);
            Class value = annotation.value();
            List<Object> obs = new ArrayList<>();
            if(forms.containsKey(name)){
                String[] fv = forms.get(name);
                for (String v : fv) {
                    Object ob = value.newInstance();
                    Method setId = value.getDeclaredMethod("setId", Integer.class);
                    Object ol = changeType(Integer.class, v);
                    setId.invoke(ob, ol);
                    obs.add(ob);
                }
                //调用方法
                method.invoke(o, obs);
            }
        }
    }

    /**
     * 类型转换
     * @param clz 类型
     * @param o 转换的对象
     * @return 转换后的对象
     */
    private Object changeType(Class clz, String o) {
        Object obj = null;
        switch (clz.toString()) {
            case ("class java.lang.String"):
                obj = o;
                break;
            case ("class java.lang.Integer"):
                obj = Integer.parseInt(o);
                break;
            case ("class java.util.Date"):
                SimpleDateFormat sf = new SimpleDateFormat("yyyy-mm-dd");
                try {
                    Date date = sf.parse(o);
                    java.sql.Date dt = new java.sql.Date(date.getTime());
                    obj = dt;
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                break;
            case ("class java.lang.Boolean"):
                Boolean b = true;
                if (o.equals("否")) {
                    b = false;
                }
                obj = b;
                break;
//            case ("class java.sql.Timestamp"):
//                Timestamp ts = new Timestamp(System.currentTimeMillis());
//                try {
//                    sf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
//                    Date date = sf.parse(o);
//                    obj = Timestamp.valueOf(date.toString());
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//                break;
        }
        return obj;
    }

}
